package com.orange.common.page;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 分页参数基类（优化版）
 */
@Data
@Slf4j
public class PageParam {
    /**
     * 当前页码，默认1
     */
    @Min(value = 1, message = "页码不能小于1")
    private Integer page = 1;

    /**
     * 每页数量，默认10（最大不超过100）
     */
    @Min(value = 1, message = "每页数量不能小于1")
    @Max(value = 100, message = "每页数量不能超过100")
    private Integer size = 10;

    /**
     * 排序字段集合（格式支持：field,direction 或 field:direction）
     */
    private List<Order> orders;

    // 无参构造函数
    public PageParam() {
        this.orders = new ArrayList<>();
    }

    /**
     * 从 HttpServletRequest 自动提取分页参数
     */
    public PageParam(HttpServletRequest request) {
        this();
        this.initFromRequest(request);
    }

    /**
     * 初始化分页参数
     */
    public void initFromRequest(HttpServletRequest request) {
        // 提取 page 参数
        String pageStr = request.getParameter("page");
        if (StringUtils.hasText(pageStr)) {
            try {
                this.page = Integer.parseInt(pageStr);
            } catch (NumberFormatException ignore) {
                log.warn("Invalid page parameter: {}", pageStr);
            }
        }

        // 提取 size 参数
        String sizeStr = request.getParameter("size");
        if (StringUtils.hasText(sizeStr)) {
            try {
                this.size = Integer.parseInt(sizeStr);
            } catch (NumberFormatException ignore) {
                log.warn("Invalid size parameter: {}", sizeStr);
            }
        }

        // 支持多种排序参数名
        String[] sortParams = null;
        if (request.getParameterValues("sort") != null) {
            sortParams = request.getParameterValues("sort");
        } else if (request.getParameterValues("orderBy") != null) {
            sortParams = request.getParameterValues("orderBy");
        } else if (request.getParameterValues("sortField") != null) {
            sortParams = request.getParameterValues("sortField");
        }

        if (sortParams != null && sortParams.length > 0) {
            for (String sortParam : sortParams) {
                Order order = parseOrder(sortParam);
                if (order != null) {
                    this.orders.add(order);
                }
            }
        }

        // 也支持单独的方向参数
        String direction = request.getParameter("direction");
        String orderField = request.getParameter("orderField");
        if (StringUtils.hasText(orderField) && StringUtils.hasText(direction)) {
            this.orders.add(new Order(orderField, Order.Direction.fromString(direction)));
        }

        log.debug("Initialized PageParam from request: {}", this);
    }

    /**
     * 转换为MyBatis-Plus的Page对象（使用默认字段映射）
     */
    public <T> Page<T> toPage() {
        return toPage(this::defaultFieldMapper);
    }

    /**
     * 转换为MyBatis-Plus的Page对象（支持字段映射）
     */
    public <T> Page<T> toPage(Function<String, String> fieldMapper) {
        log.debug("Converting PageParam to MyBatis-Plus Page: page={}, size={}, orders={}",
                page, size, orders);

        Page<T> pageObj = new Page<>(this.page, this.size);

        if (this.orders != null && !this.orders.isEmpty()) {
            List<OrderItem> orderItems = this.orders.stream()
                    .map(order -> {
                        OrderItem item = order.toOrderItem(fieldMapper);
                        log.debug("Mapped order: {} -> {}", order, item);
                        return item;
                    })
                    .collect(Collectors.toList());
            pageObj.setOrders(orderItems);
        }

        return pageObj;
    }

    /**
     * 默认字段映射：驼峰转下划线
     */
    private String defaultFieldMapper(String field) {
        return field.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
    }

    /**
     * 解析排序参数（支持多种分隔符）
     */
    private Order parseOrder(String orderStr) {
        if (!StringUtils.hasText(orderStr)) {
            return null;
        }

        String[] parts;
        if (orderStr.contains(",")) {
            parts = orderStr.split(",");
        } else if (orderStr.contains(":")) {
            parts = orderStr.split(":");
        } else {
            // 默认升序
            return new Order(orderStr.trim(), Order.Direction.ASC);
        }

        if (parts.length >= 1) {
            String field = parts[0].trim();
            Order.Direction direction = parts.length >= 2 ?
                    Order.Direction.fromString(parts[1].trim()) : Order.Direction.ASC;
            return new Order(field, direction);
        }

        return null;
    }

    /**
     * 排序项
     */
    @Data
    @AllArgsConstructor
    public static class Order {
        private String field;
        private Direction direction;

        /**
         * 转换为MyBatis-Plus的OrderItem（支持字段映射）
         */
        public OrderItem toOrderItem(Function<String, String> fieldMapper) {
            String mappedField = fieldMapper != null ? fieldMapper.apply(field) : field;
            return direction == Direction.DESC ?
                    OrderItem.desc(mappedField) : OrderItem.asc(mappedField);
        }

        public enum Direction {
            ASC, DESC;

            public static Direction fromString(String value) {
                if (value == null) return ASC;

                value = value.trim().toLowerCase();
                if (value.startsWith("desc")) {
                    return DESC;
                }
                return ASC;
            }
        }

        @Override
        public String toString() {
            return field + " " + direction;
        }
    }

    @Override
    public String toString() {
        return "PageParam{page=" + page + ", size=" + size + ", orders=" + orders + "}";
    }
}